#include "main.h"

using namespace std;

int main(int argc, char *argv[]){
    int j = 0,k;
    bool flag = true;
    if(argc==1){
        printHelp();
        return 0;
    }
    cout<<"Now analysising... "<<argv[1]<<endl;
    cout<<"Init...\t Push # in stack"<<endl;
    initPAT();
    printPAT();
    push(H);
    push(E);
    a = Parse(argv[1][j]);
    X = getTop();
    while(flag){
        cout<<"flag:"<<flag<<"\ta:"<<format(a)<<"\tX:"<<format(X)<<"\tnow:"<<now<<endl;
        for(int n = 1; n <= now; n++){
            cout<<"\033[32m"<<format(mStack[n])<<"\033[0m ";
        }
        cout<<endl;
        if(isEnd(X)){
            if(X==a && X==H){
                flag = false;
            }else if(X==a && X!=H){
                pop();
                a = Parse(argv[1][++j]);
            }else{
                // 出错
                printError();
                return -1;
            }
        }else{

            k = getNumOfPAT(X, a);
            if(k==-1){  // 错误
                cout<<"k=-1"<<endl;
                return -1;
            }else{
                pop();
                if(PAT[k].expression.isError == CORRECT){
                    if(PAT[k].expression.right[0] != e){
                        int m = 0;
                        while(m<5){
                            push(PAT[k].expression.right[4-m++]);
                        }
                    }else{
                        cout<<"\t\t\tDo nothing!"<<endl;
                    }
                }else{  // 调用出错诊断程序
                    printError();
                    return -1;
                }
            }
        }
        X = getTop();
    }
    cout<<"\033[32mCongratulation! Your input is correct!\033[0m"<<endl;
    return 0;
}

/**
 * 初始化预测分析表，这一个步骤应该调用预测分析表构造程序，这里只是赋值
*/
void initPAT(){
    count = 0;
    SYMBOL exps[7][5] = {
        {T,_,e,e,e},
        {F,t,e,e,e},
        {i,e,e,e,e},
        {P,T,_,e,e},
        {e,e,e,e,e},
        {M,F,t,e,e},
        {L,E,R,e,e}
    };
    insertPAT(E,i,initNode(E,2,CORRECT,exps[0]));
    insertPAT(_,i,initNode(e,0,ERROR,exps[0]));
    insertPAT(T,i,initNode(T,2,CORRECT,exps[1]));
    insertPAT(t,i,initNode(e,0,ERROR,exps[0]));
    insertPAT(F,i,initNode(F,1,CORRECT,exps[2]));

    insertPAT(E,P,initNode(e,0,ERROR,exps[0]));
    insertPAT(_,P,initNode(_,3,CORRECT,exps[3]));
    insertPAT(T,P,initNode(e,0,ERROR,exps[0]));
    insertPAT(t,P,initNode(t,1,CORRECT,exps[4]));
    insertPAT(F,P,initNode(e,0,ERROR,exps[0]));

    insertPAT(E,M,initNode(e,0,ERROR,exps[0]));
    insertPAT(_,M,initNode(e,0,ERROR,exps[0]));
    insertPAT(T,M,initNode(e,0,ERROR,exps[0]));
    insertPAT(t,M,initNode(t,3,CORRECT,exps[5]));
    insertPAT(F,M,initNode(e,0,ERROR,exps[0]));

    insertPAT(E,L,initNode(E,2,CORRECT,exps[0]));
    insertPAT(_,L,initNode(e,0,ERROR,exps[0]));
    insertPAT(T,L,initNode(T,2,CORRECT,exps[1]));
    insertPAT(t,L,initNode(e,0,ERROR,exps[0]));
    insertPAT(F,L,initNode(F,1,CORRECT,exps[6]));

    insertPAT(E,R,initNode(e,0,ERROR,exps[0]));
    insertPAT(_,R,initNode(_,1,CORRECT,exps[4]));
    insertPAT(T,R,initNode(e,0,ERROR,exps[0]));
    insertPAT(t,R,initNode(t,1,CORRECT,exps[4]));
    insertPAT(F,R,initNode(e,0,ERROR,exps[0]));

    insertPAT(E,H,initNode(e,0,ERROR,exps[0]));
    insertPAT(_,H,initNode(_,1,CORRECT,exps[4]));
    insertPAT(T,H,initNode(e,0,ERROR,exps[0]));
    insertPAT(t,H,initNode(t,1,CORRECT,exps[4]));
    insertPAT(F,H,initNode(e,0,ERROR,exps[0]));
}

void insertPAT(SYMBOL x, SYMBOL y, NODE expression){
    PAT[count].x = x;
    PAT[count].y = y;
    PAT[count].expression = expression;
    count++;
}

NODE initNode(SYMBOL left, int num, int isError, SYMBOL right[]){
    static NODE tmp;
    int j;
    tmp.left = left;
    for(j = 0;j<5;j++){
        tmp.right[j] = right[j];
    }

    tmp.isError = isError;
    return tmp;
}

void printPAT(){
    for(int j = 0; j < count; j++){
        cout<<"x:\t"<<format(PAT[j].x)<<"\ty:\t"<<format(PAT[j].y)<<endl;
        cout<<"\tisError:\t"<<PAT[j].expression.isError<<"\tleft:\t"<<format(PAT[j].expression.left);
        cout<<"\tright:\t";
        for(int k = 0;k<5;k++){
            cout<<format(PAT[j].expression.right[k]);
        }
        cout<<endl;
    }
}

void printHelp(){
    cout<<endl;
    cout<<"\tWelcome To Use MaoMao Prediction-analysis Programe!\t"<<endl;
    cout<<"Usage:\t./test [expression#]"<<endl;
    cout<<"If expression is null, show this page!"<<endl;
    cout<<"Have a try with:\t \033[1m./test i*i+i#\033[0m"<<endl;
    cout<<"Note: your expression must end with #, or throw an Error"<<endl;
    cout<<endl;
}

void push(SYMBOL x){
    cout<<"\033[33mTry PUSH"<<format(x)<<"\033[0m"<<endl;
    if(x!=e){
        mStack[++now] = x;
        cout<<"\033[33mPUSH: now = "<<now<<"\tvalue="<<format(mStack[now])<<"\033[0m"<<endl;
    }
}

SYMBOL pop(){
    now = now - 1;
    cout<<"\033[33mPOP: now = "<<now<<"\tvalue="<<format(mStack[now])<<"\033[0m"<<endl;
    return mStack[now];
}

SYMBOL getTop(){
    return mStack[now];
}

bool isEnd(SYMBOL x){
    switch(x){
        case E:
        case _:
        case T:
        case t:
        case F:
            return false;
            break;
        case i:
        case P:
        case M:
        case L:
        case R:
        case H:
            return true;
            break;
    }
}

int getNumOfPAT(SYMBOL x, SYMBOL y){
    int j = 0;
    while(j<count){
        if(PAT[j].x == x && PAT[j].y == y){
            return j;
        }else{
            j++;
        }
    }
    return -1;
}

SYMBOL Parse(char c){
    cout<<"Parse A..."<<c<<endl;
    if(c == '+')return P;
    if(c == '*')return M;
    if(c == '(')return L;
    if(c == ')')return R;
    if(c == '#')return H;
    return i;
}

void printError(){
    cerr<<"\033[31mError:\ta:"<<format(a)<<"\tX:"<<format(X)<<"\033[0m"<<endl;
}

char format(SYMBOL x){
    switch(x){
        case i:
            return 'i';
        case P:
            return '+';
        case M:
            return '*';
        case L:
            return '(';
        case R:
            return ')';
        case H:
            return '#';
        case E:
            return 'E';
        case T:
            return 'T';
        case F:
            return 'F';
        case _:
            return '_';
        case t:
            return 't';
        default:
            return '-';
    }
}
